# This file is part of PyMXit, a Python library implementing the basic
# functionality of the MXit protocol.
#
# Copyright (C) 2008 Ralf Kistner <ralf.kistner@gmail.com>
# 
# PyMXit is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# PyMXit is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with PyMXit.  If not, see <http://www.gnu.org/licenses/>.

from mxit.commands import Client, Server, Binary
from mxit.handles import *

from mxit.server.listener import Listener

def parse(data):
    tokens = {}
    for s in data.split("\x00"):
        e = s.find("=")
        if e == -1:
            continue
        name = s[:e]
        value = s[e+1:]
        tokens[name] = parse_value(value)
    
    return tokens

def parse_value(value):
    return map(lambda s: s.split('\1'), value.split('\0'))


def encode_string(string):
    if hasattr(string, 'encode'):
        return string.encode("ISO-8859-1")
    else:
        return str(string).encode("ISO-8859-1")
    
def build_command(data):
    """ Build a command for sending. """
    cmds = []
    for cmd in data:
        bits = []
        for a in cmd:
            if isinstance(a, (tuple, list)):
                bits.append('\1'.join(map(encode_string, a)))
            else:
                bits.append(encode_string(a))
        cmds.append('\0'.join(bits))
    f = '\2'.join(cmds)
    
    return "ln=%d\0%s" % (len(f), f)

    
class ServerConnection:
    def __init__(self, socket):
        self.socket = socket
        self.buffer = ""
        self.req = 0
        
        self.roster = Roster()        
        services = self.roster.get_group('Services')
        buddies = self.roster.get_group('Buddies')
        root = self.roster.root_group()
        self.roster.add_buddy(Buddy('info@mxit.co.za', 'Info', group=root, type=BuddyType.INFO, presence=Presence.AVAILABLE))
        self.roster.add_buddy(Buddy('gallery@mxit.co.za', 'Gallery', group=services, type=BuddyType.GALLERY, presence=Presence.AVAILABLE))
        self.roster.add_buddy(Buddy('service@mxit.co.za', 'Random service', group=services, type=BuddyType.SERVICE, presence=Presence.AVAILABLE))
        self.roster.add_buddy(Buddy('buddy@mxit.co.za', 'BUDD', group=buddies, type=BuddyType.MXIT, presence=Presence.AWAY, mood=Mood.HAPPY))
        
    
    def append(self, data):
        self.buffer += data
        print self.buffer
        if self.req == 0:
            self.recalcreq()
            
        if self.req > 0 and len(self.buffer) > self.req:
            self.got_data(data[:self.req])
            self.buffer = self.buffer[:self.req]
            self.recalcreq()
            
    def recalcreq(self):
        if len(self.buffer) > 4 and '\x00' in self.buffer:
            if not self.buffer.startswith("ln="):
                print "invalid buffer:", buffer
                self.buffer = ""
            end = self.buffer.index('\x00')
            self.req = int(self.buffer[3:end])
        else:
            self.req = 0
    
    def send_raw(self, data):
        self.socket.send(data)
    
    def send(self, data):
        self.send_multiple([data])
        
    def send_multiple(self, data):
        print "SENDING:", data
        self.send_raw(build_command(data))
    
    def send_command(self, cmd, data):
        self.send([cmd.id, 0] + data)
        
    def s_login(self):
        self.send_command(Server.LOGIN, ['testing', [123]])
        bdata = []
        for jid, buddy in self.roster.buddies.items():
            bdata.append([buddy.group.name, buddy.jid, buddy.name, buddy.presence.id, buddy.type.id, buddy.mood.id])
        self.send_command(Server.PRESENCE, bdata)
        
    def s_msg(self, buddy, message, time=0, type=MessageType.TEXT):
        self.send_command(Server.MESSAGE, [[buddy.jid, time, type.id], [message]])
        
        
    def got_data(self, data):
        command = parse(data)
        print "RECEIVED:", command
        cmd = Client.byid(int(command['cm'][0][0]))
        cmd_data = command['ms']
        if cmd == Client.LOGIN:
            self._r_login(cmd_data)
        elif cmd == Client.MESSAGE:
            self._r_message(cmd_data)
            
        #self.ch.handle(command)
    
    def listen(self):
        running = True
        while running:
            data = self.socket.recv(1024)
            if data:
                self.append(data)
            else:
                self.socket.close()
                running = False
                
                
    def _r_login(self, data):
        print "logged in"
        self.s_login()
              
    def _r_message(self, data): 
         jid, msg, type = data[0]
         print jid, msg, type
         buddy = self.roster.get_buddy(jid)
         self.s_msg(buddy, "You sent: %s" % msg)
         
              
              
                
if __name__ == "__main__":

    def cb_func((client,address)):
        print "Connected to", address
        s = ServerConnection(client)
        s.listen()
        
   # print [cmdsender.build_command([1, 2, "3", ["jou", 5], 8])]
    
    s = Listener(9119, cb_func)
    if not s.isopen():
        sys.exit(1)
    s.run()
    print "waiting for exit input..."
    #print sys.__stdin__.readline()
    print "quitting..."
    s.stop()
    print "done."